﻿using System;
using System.Reflection;
using System.Resources;

#if !PCL
using System.Collections.Concurrent;
#endif

namespace OmniKits
{
    using Utilities;

    partial class Helpers
    {
        public sealed class ResourceHelper { }
        public static ResourceHelper ResEx { get; }

        public static ResourceManager GetResourceManager(this ResourceHelper _, Type type)
            => type.GetResourceManager();
        public static ResourceManager GetResourceManager(this ResourceHelper _, string qualifiedName)
            => qualifiedName.GetResourceManager();
        public static ResourceManager GetResourceManager(this ResourceHelper _, Assembly assembly, string baseName)
            => assembly.GetResourceManager(baseName);
#if !PCL
        public static ResourceManager GetResourceManager(this ResourceHelper _, Type type, Type usingResourceSet)
            => type.GetResourceManager(usingResourceSet);
        public static ResourceManager GetResourceManager(this ResourceHelper _, string qualifiedName, Type usingResourceSet)
            => qualifiedName.GetResourceManager(usingResourceSet);
        public static ResourceManager GetResourceManager(this ResourceHelper _, Assembly assembly, string baseName, Type usingResourceSet)
            => assembly.GetResourceManager(baseName, usingResourceSet);
#endif
    }
}

namespace OmniKits.Utilities
{
    public static class ResourceUtility
    {
#pragma warning disable 1591

#if !PCL
        private static ConcurrentDictionary<Tuple<string, Type>, Lazy<ResourceManager>> ResManCache =
            new ConcurrentDictionary<Tuple<string, Type>, Lazy<ResourceManager>>();
#endif

        private static ResourceManager GetResourceManagerInternal(string qualifiedName, string baseName, Assembly assembly)
        {
#if PCL
            return new ResourceManager(baseName, assembly);
#else
            var key = Tuple.Create(qualifiedName.ToUpperInvariant(), (Type)null);

            var lazy = new Lazy<ResourceManager>(() => new ResourceManager(baseName, assembly));
            if (!ResManCache.TryAdd(key, lazy))
                lazy = ResManCache[key];

            return lazy.Value;
#endif
        }

        public static ResourceManager GetResourceManager(this Type type)
        {
            return GetResourceManagerInternal(type.AssemblyQualifiedName, type.FullName, type.Assembly);
        }

        public static ResourceManager GetResourceManager(this string qualifiedName)
        {
            // there is never a chance to locate the assembly where the actual class which used the attributes defined
            // so just forget it
            return GetResourceManager(Type.GetType(qualifiedName));
        }

        public static ResourceManager GetResourceManager(this Assembly assembly, string baseName)
        {
            return GetResourceManagerInternal(baseName.Trim() + ", " + assembly.FullName, baseName, assembly);
        }

#if !PCL
        private static ResourceManager GetResourceManagerInternal(string qualifiedName, string baseName, Assembly assembly, Type usingResourceSet)
        {
            var key = Tuple.Create(qualifiedName.ToUpperInvariant(), usingResourceSet);

            var lazy = new Lazy<ResourceManager>(() => new ResourceManager(baseName, assembly, usingResourceSet));
            if (!ResManCache.TryAdd(key, lazy))
                lazy = ResManCache[key];

            return lazy.Value;
        }

        public static ResourceManager GetResourceManager(this Type type, Type usingResourceSet)
        {
            return GetResourceManagerInternal(type.AssemblyQualifiedName, type.FullName, type.Assembly, usingResourceSet);
        }

        public static ResourceManager GetResourceManager(this string qualifiedName, Type usingResourceSet)
        {
            // there is never a chance to locate the assembly where the actual class which used the attributes defined
            // so just forget it
            return GetResourceManager(Type.GetType(qualifiedName), usingResourceSet);
        }

        public static ResourceManager GetResourceManager(this Assembly assembly, string baseName, Type usingResourceSet)
        {
            return GetResourceManagerInternal(baseName.Trim() + ", " + assembly.FullName, baseName, assembly, usingResourceSet);
        }
#endif
    }
}
